package fr.jade.fraclite.control.binding;

import java.util.HashMap;
import java.util.Map;

import org.objectweb.fractal.api.Component;
import org.objectweb.fractal.api.Interface;
import org.objectweb.fractal.api.NoSuchInterfaceException;
import org.objectweb.fractal.api.control.BindingController;
import org.objectweb.fractal.api.control.ContentController;
import org.objectweb.fractal.api.control.IllegalBindingException;
import org.objectweb.fractal.api.control.IllegalLifeCycleException;
import org.objectweb.fractal.api.factory.InstantiationException;
import org.objectweb.fractal.api.type.InterfaceType;

import fr.jade.fraclite.InitializationContext;
import fr.jade.fraclite.api.ComponentInterface;
import fr.jade.fraclite.api.Controller;

/**
 * Provides a basic implementation of the {@link BindingController} interface.
 * This mixin uses a map to store the bindings of the component.
 * <br>
 * <br>
 * <b>Requirements</b>
 * <ul>
 * <li>none.</li>
 * </ul>
 */

public class BasicBindingController implements Controller, BindingController {

  /**
   * The bindings of the component to which this controller object belongs.
   * This map associates to each client interface name the server interface to
   * which it is bound. If a client interface is not bound, its name is not
   * associated to <tt>null</tt>, but to the {@link #fcBindings} map itself.
   * This way the {@link #listFc listFc} method returns the names of all the
   * client interfaces of the component, and not only the names of the
   * interfaces that are bound.
   */

  protected Map<String, Object> fcBindings = null;

  protected BindingController innerImpl = null;
  
  protected Component weaveableC = null;
  
  protected ContentController weaveableCC = null;
  
  public void initFcController(InitializationContext ic) throws InstantiationException {
    weaveableC = (Component) ic.getInterface("component");
    if (ic.content == null){
      fcBindings = new HashMap<String, Object>();
      weaveableCC = (ContentController) ic.getInterface("content-controller");
    }
    if(ic.content instanceof BindingController){
      innerImpl = (BindingController) ic.content;
    }
  }
  
  public String[] listFc () {
    if (innerImpl != null) {
      return innerImpl.listFc();
    }else{
      return (String[])fcBindings.keySet().toArray(new String[fcBindings.size()]);
    }
  }

  public Object lookupFc (final String clientItfName) throws NoSuchInterfaceException {
    if (innerImpl != null) {
      return innerImpl.lookupFc(clientItfName);
    }else{
      Object serverItf = fcBindings.get(clientItfName);
      return serverItf == fcBindings ? null : serverItf;
    }
  }

  public void bindFc (final String clientItfName, final Object serverItf) throws NoSuchInterfaceException, IllegalBindingException, IllegalLifeCycleException {
    if (innerImpl != null) {
      innerImpl.bindFc(clientItfName, serverItf);
    }else{
      fcBindings.put(clientItfName, serverItf);
      updateInterfaceImpl(clientItfName, serverItf);
    }
  }

  public void unbindFc (final String clientItfName) throws NoSuchInterfaceException, IllegalBindingException, IllegalLifeCycleException {
    if (innerImpl != null) {
      innerImpl.unbindFc(clientItfName);
    }else{
      fcBindings.put(clientItfName, fcBindings);
      updateInterfaceImpl(clientItfName, null);
    }
  }

  protected void updateInterfaceImpl(String clientItfName, Object serverItf) throws NoSuchInterfaceException {
    Interface itf = (Interface) weaveableC.getFcInterface(clientItfName);
    InterfaceType clientItfType = (InterfaceType) itf.getFcItfType();
    ComponentInterface complementaryItf = null;
    if (clientItfType.isFcClientItf()) {
      complementaryItf = (ComponentInterface)weaveableCC.getFcInternalInterface(clientItfName);
    } else {
      complementaryItf = (ComponentInterface)weaveableC.getFcInterface(clientItfName);
    }
    ((ComponentInterface)complementaryItf).setFcItfImpl(serverItf);
  }

}
